package stu.officedrunker.applications.common.model;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;

/**
 * 간단한 코드 처리를 위한 추상 클래스.
 * @author 서성수
 */
public abstract class CodeSupport {

	/**
	 * Return code value list
	 * 
	 * @param codeType
	 *            code type
	 * @return code value list
	 */
	public static String[] values(Class<? extends CodeSupport> codeType) {
		if (codeType == null)
			throw new NullPointerException("CodeType is null");

		List<String> values = new ArrayList<String>();
		for (Field field : codeType.getDeclaredFields()) {
			int modifiers = field.getModifiers();
			if (Modifier.isTransient(modifiers))
				continue;
			if (!Modifier.isPublic(modifiers))
				continue;
			if (!Modifier.isStatic(modifiers))
				continue;
			if (!CharSequence.class.isAssignableFrom(field.getType()))
				continue;
			try {
				Object value = field.get(null);
				if (value != null) {
					values.add(value.toString());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return values.toArray(new String[values.size()]);
	}

	/**
	 * @param <T>
	 *            code type
	 * @param codeType
	 *            code type class
	 * @param code
	 *            code value
	 * @return code type instance
	 * @throws IllegalArgumentException
	 */
	public static <T extends CodeSupport> T valueOf(Class<T> codeType, String code) {
		if (codeType == null)
			throw new NullPointerException("CodeType is null");
		if (code == null)
			throw new NullPointerException("Code is null");
		if (ArrayUtils.contains(values(codeType), code)) {
			try {
				Constructor<T> constructor = codeType.getDeclaredConstructor(String.class);
				constructor.setAccessible(true);
				return constructor.newInstance(code);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		throw new IllegalArgumentException("No code const " + codeType + "." + code);
	}

	private String value;

	protected CodeSupport(String value) {
		if (value == null)
			throw new NullPointerException("Value is null");
		this.value = value;
	}

	public String value() {
		return value;
	}

	@Override
	public String toString() {
		return value;
	}

	@Override
	public final boolean equals(Object other) {
		if (this == other)
			return true;
		if (other == null)
			return false;
		if (!this.getClass().equals(other.getClass()))
			return false;
		if (this.value.equals(((CodeSupport) other).value))
			return true;
		return false;
	}

	public final int hashCode() {
		return value.hashCode();
	}

}
